from contextlib import contextmanager
from flask_sqlalchemy import SQLAlchemy as _SQLAlchemy, BaseQuery
from datetime import datetime


class SQLAlchemy(_SQLAlchemy):
    ''' 给当前db对象增加一个自动提交的方法,所以在SQLAlchemy中新增加一个方法.
        优点: 减少重复代码的书写,B格比较高(面向对象的好处,只要我想要新增一些方法,只要继承原来的类就可以了)
        缺点: 假如失败以后需要返回一些特定的error提示给到前段,这种写法不太灵活.'''
    @contextmanager
    def auto_commit(self):
        ''' contextmanager可以让一个函数不需要自己实现__enter__和__exit__魔法方法,快速创建一个上下文管理器
            上下文管理器: 对资源进行的管理的一种手段,数据库资源,文件资源等等 '''
        try:
            yield # 暂停执行业务逻辑.
            self.session.commit()
        except Exception as e:
            self.session.rollback()
            raise e


class Query(BaseQuery):
    ''' 这里我们希望filter_by方法在查询的时候默认加入一个条件,所以要重写这个方法
        完成需要的逻辑以后,还要调用原来的逻辑方法,使用super()函数'''
    def filter_by(self, **kwargs):
        kwargs['status'] = 1
        return super(Query, self).filter_by(**kwargs)


db = SQLAlchemy(query_class=Query) # 使用自定义的query对象.


class Base(db.Model):
    __abstract__ = True # 不生成模型类
    create_time = db.Column(db.DateTime)
    status = db.Column(db.SmallInteger, default=1)

    def __init__(self):
        ''' 因为create_time是类属性,我们如果不对类属性进行修改,它的值是全局不变的
            所以在__init__中动态赋值,在每一次对象的创建时.'''
        self.create_time = datetime.now()

    def set_attrs(self, attrs_dict):
        ''' 对象属性的快速赋值,可以借鉴
            前提: 传过来的dict保证和对象的属性名是相同的 '''
        for key, value in attrs_dict.items():
            if hasattr(self, key) and key != 'id':
                # 动态赋值(对象, 属性, 值)
                setattr(self, key, value)

    def delete(self):
        self.status = 0